package com.zs.toolbox.web2j.common.web;

import com.alibaba.fastjson.JSONObject;
import com.zs.toolbox.web2j.common.exception.WtBaseException;
import com.zs.toolbox.web2j.common.exception.WtExceptions;
import com.zs.toolbox.web2j.common.exception.WtResponses;
import com.zs.toolbox.web2j.common.response.WtBaseResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.Set;

/**
 * @author: hxy
 * @description: 统一异常拦截
 * @date: 2017/10/24 10:31
 */
@RestControllerAdvice
public class WtGlobalExceptionHandler {
    private Logger logger = LoggerFactory.getLogger("GlobalExceptionHandler");


    /**
     * GET/POST请求方法错误的拦截器
     * 因为开发时可能比较常见,而且发生在进入controller之前,上面的拦截器拦截不到这个错误
     * 所以定义了这个拦截器
     *
     * @return
     * @throws Exception
     */
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public WtBaseResponse httpRequestMethodHandler() throws Exception {
        return WtResponses.E_PATH;
    }


    /**
     * 本系统自定义错误的拦截器
     * 拦截到此错误之后,就返回这个类里面的json给前端
     * 常见使用场景是参数校验失败,抛出此错,返回错误信息给前端
     *
     * @param cmUserException
     * @return
     */
    @ExceptionHandler(WtBaseException.class)
    public WtBaseResponse commonJsonExceptionHandler(WtBaseException cmUserException) {
        return cmUserException.errorResponse();
    }


    @ExceptionHandler(ConstraintViolationException.class)
    public WtBaseResponse handleConstraintViolationException(ConstraintViolationException cve) {
        Set<ConstraintViolation<?>> cves = cve.getConstraintViolations();
        for (ConstraintViolation<?> constraintViolation : cves) {
            return new WtBaseResponse(1000, constraintViolation.getMessage());
        }
        return WtResponses.SUCCESS;
    }

    @ExceptionHandler(value= DuplicateKeyException.class)
    public WtBaseResponse handleDuplicateKeyException(DuplicateKeyException cve) {
        return WtExceptions.E_COMMON_KEY_EXIST.errorResponse();
    }

    @ExceptionHandler(value = Exception.class)
    public WtBaseResponse defaultErrorHandler(HttpServletRequest req, Exception e) throws Exception {
        if(e instanceof AccessDeniedException) {
            throw e;
        }

        String errorPosition = "";
        //如果错误堆栈信息存在
        if (e.getStackTrace().length > 0) {
            StackTraceElement element = e.getStackTrace()[0];
            String fileName = element.getFileName() == null ? "未找到错误文件" : element.getFileName();
            int lineNumber = element.getLineNumber();
            errorPosition = fileName + ":" + lineNumber;
        }

        JSONObject errorObject = new JSONObject();
        errorObject.put("errorLocation", e.toString() + "    错误位置:" + errorPosition);
        logger.error("异常", e);
        return new WtBaseResponse(WtResponses.E_INTER.status, WtResponses.E_INTER.message, errorObject);
    }
}